from rest_framework.exceptions import PermissionDenied

from prj001.models.cure import Cure
from prj001.models.geninfo import GeneralInfo

from prj001.constants import cure_info_necessary


def computed_cure(data=None, tps=None, _ID=None):
    """
    calculate cure info
    data: need to compute
    type: if object need to __dict__; else dict
    """
    if tps == 'object' and _ID is not None:
        try:
            data = Cure.objects.get(person_id=_ID)
        except Cure.DoesNotExist:
            data = None
    if not data:
        return 0
    cure_of_list = list()

    for index, value in enumerate(cure_info_necessary):
        son_list_in_cure = []
        for i, v in enumerate(value):
            if tps == 'object':
                v_info = data.__dict__.get(v)
            else:
                v_info = data.get(v)

            if v_info:
                son_list_in_cure.append(v)
        if son_list_in_cure:
            cure_of_list.append(son_list_in_cure)

    degree = (len(cure_of_list) / len(cure_info_necessary)) * 0.5

    return degree


def update_model(data, tps=None, user=None):
    """
    ==> calculate degree
    data: object or dict,
    tps: object if type,
    user: if object => user=None; else user
    """
    from prj001.constants import gen_info_necessary
    now_list = []
    if user:
        now_list.append('owner_id')
    for i, g in enumerate(gen_info_necessary):
        if not tps:
            result = data.get(g, None)
        else:
            result = data.__dict__.get(g, None)
        if result:
            now_list.append(result)

    degree = (len(now_list) / len(gen_info_necessary)) * 0.5
    return degree


def inner_create_model(data, obj=None, user=None, types=None):
    o = obj(owner=user, **data)
    o.save()
    if types == 'cure_degree':
        gen_obj = GeneralInfo.objects.get(id=o.person_id)
        cure_degree = computed_cure(data=o, tps='object')
        info_degree = update_model(gen_obj, tps='info')
        gen_obj.degree_of_completion = '%.2f%%' % ((cure_degree + info_degree) * 100)
        gen_obj.is_checked = '未审核'
        gen_obj.save()
    return o


def create_model(sf, data, obj=None, tps=None):
    user = sf.context['view'].request.user
    person = data['person']

    is_self = user.has_perm('prj001.prj001_operation')
    is_all = user.has_perm('prj001.prj001_all')

    if is_all:
        return inner_create_model(data, user=user, obj=obj, types=tps)
    elif is_self:

        if person.owner == user:
            return inner_create_model(data, user=user, obj=obj, types=tps)
        else:
            if person.owner:
                data = {
                    'msg': '对不起,您没有创建的权限.如需创建,请联系 %s' % (person.owner.email)
                }
            raise PermissionDenied(detail=data)


def update_every_table(instance, data, tps=None, user=None, is_checked='未审核'):
    """ update info only currently: type => diff of decorators"""

    if tps != 'info':
        try:
            gen_obj = GeneralInfo.objects.get(id=instance.person_id)
        except GeneralInfo.DoesNotExist:
            raise ValueError('无对应的一般信息')
        info_degree = update_model(gen_obj, tps='info')
        cure_degree = computed_cure(data=data)

    instance_id = instance.id

    for key, ins in instance.__dict__.items():
        if isinstance(ins, str):
            instance.__dict__[key] = None

    if tps == 'info':
        cure_degree = computed_cure(tps='object', _ID=instance_id)
        info_degree = update_model(data, user=instance.owner)
        instance.__dict__.update(is_checked=is_checked,
                                 degree_of_completion='%.2f%%' % ((cure_degree + info_degree) * 100),
                                 **data)
    elif tps == 'cure_degree':
        gen_obj.degree_of_completion = '%.2f%%' % ((cure_degree + info_degree) * 100)
        gen_obj.is_checked = is_checked
        gen_obj.save()
        instance.__dict__.update(**data)
    else:
        gen_obj.is_checked = is_checked
        gen_obj.save()
        instance.__dict__.update(**data)
    instance.save()
    return instance
